# MetadataSolvingCache.java

    package org.codefilarete.stalactite.engine.configurer.dslresolver;

    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;

    import org.codefilarete.stalactite.engine.configurer.dslresolver.InheritanceConfigurationResolver.ResolvedConfiguration;
    import org.codefilarete.stalactite.engine.configurer.model.Entity;
    import org.codefilarete.stalactite.sql.ddl.structure.Table;
    import org.codefilarete.tool.collection.KeepOrderSet;

    public class MetadataSolvingCache {

    	private final Map<Entity<?, ?, ?>, EntitySource<?, ?>> entityBuildSources = new HashMap<>();

    	public <X, I> void put(Entity<X, I, ?> entity, EntitySource<X, I> entitySource) {
    		entityBuildSources.put(entity, entitySource);
    	}

    	public boolean containsEntityType(Class<?> entityType) {
    		return entityBuildSources.containsKey(entityType);
    	}

    	/**
    	 * Since there's no exact matching between entity and {@link ResolvedConfiguration}, in particular when
    	 * dealing with inheritance, we need to keep track of ancestor configurations to resolve the final configuration.
    	 *
    	 * @param <C>
    	 * @param <I>
    	 * @author Guillaume Mary
    	 */
    	public static class EntitySource<C, I> {

    		private final Entity<C, I, ?> entity;

    		private final Set<ResolvedConfiguration<C, I>> resolvedConfigurations = new KeepOrderSet<>();

    		private final Set<EntitySource<?, I>> ancestorSources = new KeepOrderSet<>();

    		EntitySource(Entity<C, I, ?> entity, ResolvedConfiguration<C, I> resolvedConfiguration) {
    			this.entity = entity;
    			this.resolvedConfigurations.add(resolvedConfiguration);
    		}

    		public <T extends Table<T>> Entity<C, I, T> getEntity() {
    			return (Entity<C, I, T>) entity;
    		}

    		public Set<ResolvedConfiguration<C, I>> getResolvedConfigurations() {
    			return resolvedConfigurations;
    		}

    		public <X> void addSource(Entity<X, I, ?> entityOrAncestor, ResolvedConfiguration<X, I> ancestorSource) {
    			if (entityOrAncestor == entity){
    				resolvedConfigurations.add((ResolvedConfiguration<C, I>) ancestorSource);
    			} else {
    				// looking for the ancestor sources of the given entity
    				EntitySource<X, I> foundAncestorSource = findAncestorSource(entityOrAncestor);
    				if (foundAncestorSource == null) {
    					ancestorSources.add(new EntitySource<>(entityOrAncestor, ancestorSource));
    				} else {
    					foundAncestorSource.resolvedConfigurations.add(ancestorSource);
    				}
    			}
    		}

    		public <X> Set<EntitySource<X, I>> getAncestorSources() {
    			return (Set<EntitySource<X, I>>) (Set) ancestorSources;
    		}

    		public <X /* super C */> EntitySource<X, I> findAncestorSource(Entity<X, I, ?> ancestor) {
    			return (EntitySource<X, I>) ancestorSources.stream()
    					.filter(s -> s.entity == ancestor)
    					.findFirst()
    					.orElse(null);
    		}
    	}
    }